import { ref, watch, onUnmounted, type Ref } from 'vue'

// 防抖配置
export interface DebounceConfig {
  delay?: number
  immediate?: boolean
  maxWait?: number
}

// 节流配置
export interface ThrottleConfig {
  delay?: number
  leading?: boolean
  trailing?: boolean
}

// 防抖函数类型
export type DebouncedFunction<T extends (...args: any[]) => any> = {
  (...args: Parameters<T>): void
  cancel: () => void
  flush: () => void
  pending: () => boolean
}

// 节流函数类型
export type ThrottledFunction<T extends (...args: any[]) => any> = {
  (...args: Parameters<T>): void
  cancel: () => void
  flush: () => void
  pending: () => boolean
}

// 防抖函数实现
export const debounce = <T extends (...args: any[]) => any>(
  func: T,
  delay: number = 300,
  options: Omit<DebounceConfig, 'delay'> = {}
): DebouncedFunction<T> => {
  const { immediate = false, maxWait } = options
  
  let timeoutId: NodeJS.Timeout | null = null
  let maxTimeoutId: NodeJS.Timeout | null = null
  let lastCallTime: number | null = null
  let lastInvokeTime = 0
  let lastArgs: Parameters<T> | null = null
  let result: ReturnType<T>
  
  const invokeFunc = (time: number): ReturnType<T> => {
    const args = lastArgs!
    lastArgs = null
    lastInvokeTime = time
    result = func.apply(null, args)
    return result
  }
  
  const leadingEdge = (time: number): ReturnType<T> => {
    lastInvokeTime = time
    timeoutId = setTimeout(timerExpired, delay)
    return immediate ? invokeFunc(time) : result
  }
  
  const remainingWait = (time: number): number => {
    const timeSinceLastCall = time - lastCallTime!
    const timeSinceLastInvoke = time - lastInvokeTime
    const timeWaiting = delay - timeSinceLastCall
    
    return maxWait !== undefined
      ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)
      : timeWaiting
  }
  
  const shouldInvoke = (time: number): boolean => {
    const timeSinceLastCall = time - lastCallTime!
    const timeSinceLastInvoke = time - lastInvokeTime
    
    return (
      lastCallTime === null ||
      timeSinceLastCall >= delay ||
      timeSinceLastCall < 0 ||
      (maxWait !== undefined && timeSinceLastInvoke >= maxWait)
    )
  }
  
  const timerExpired = (): ReturnType<T> | void => {
    const time = Date.now()
    if (shouldInvoke(time)) {
      return trailingEdge(time)
    }
    timeoutId = setTimeout(timerExpired, remainingWait(time))
  }
  
  const trailingEdge = (time: number): ReturnType<T> => {
    timeoutId = null
    
    if (lastArgs) {
      return invokeFunc(time)
    }
    lastArgs = null
    return result
  }
  
  const cancel = (): void => {
    if (timeoutId !== null) {
      clearTimeout(timeoutId)
    }
    if (maxTimeoutId !== null) {
      clearTimeout(maxTimeoutId)
    }
    lastInvokeTime = 0
    lastArgs = null
    lastCallTime = null
    timeoutId = null
    maxTimeoutId = null
  }
  
  const flush = (): ReturnType<T> => {
    return timeoutId === null ? result : trailingEdge(Date.now())
  }
  
  const pending = (): boolean => {
    return timeoutId !== null
  }
  
  const debounced = ((...args: Parameters<T>): void => {
    const time = Date.now()
    const isInvoking = shouldInvoke(time)
    
    lastArgs = args
    lastCallTime = time
    
    if (isInvoking) {
      if (timeoutId === null) {
        leadingEdge(lastCallTime)
        return
      }
      if (maxWait !== undefined) {
        timeoutId = setTimeout(timerExpired, delay)
        return invokeFunc(lastCallTime)
      }
    }
    if (timeoutId === null) {
      timeoutId = setTimeout(timerExpired, delay)
    }
  }) as DebouncedFunction<T>
  
  debounced.cancel = cancel
  debounced.flush = flush
  debounced.pending = pending
  
  return debounced
}

// 节流函数实现
export const throttle = <T extends (...args: any[]) => any>(
  func: T,
  delay: number = 300,
  options: Omit<ThrottleConfig, 'delay'> = {}
): ThrottledFunction<T> => {
  const { leading = true, trailing = true } = options
  
  return debounce(func, delay, {
    maxWait: delay,
    immediate: leading
  }) as ThrottledFunction<T>
}

// 防抖 Composable
export const useDebounce = <T>(
  value: Ref<T> | T,
  delay: number = 300,
  options: Omit<DebounceConfig, 'delay'> = {}
) => {
  const { immediate = false } = options
  
  const debouncedValue = ref<T>(typeof value === 'object' && value != null && 'value' in value ? value.value : value) as Ref<T>
  const isPending = ref(false)
  
  let timeoutId: NodeJS.Timeout | null = null
  
  const updateValue = (newValue: T) => {
    debouncedValue.value = newValue
    isPending.value = false
  }
  
  const debouncedUpdate = debounce(updateValue, delay, options)
  
  // 如果传入的是 ref，监听其变化
  if (typeof value === 'object' && value && 'value' in value) {
    watch(
      value,
      (newValue) => {
        isPending.value = true
        if (newValue != null && immediate && !debouncedUpdate.pending()) {
          updateValue(newValue)
        } else if (newValue != null) {
          debouncedUpdate(newValue)
        }
      },
      { immediate: true }
    )
  }
  
  // 手动设置值
  const setValue = (newValue: T) => {
    isPending.value = true
    if (immediate && !debouncedUpdate.pending()) {
      updateValue(newValue)
    } else {
      debouncedUpdate(newValue)
    }
  }
  
  // 取消防抖
  const cancel = () => {
    debouncedUpdate.cancel()
    isPending.value = false
  }
  
  // 立即执行
  const flush = () => {
    debouncedUpdate.flush()
    isPending.value = false
  }
  
  // 清理
  onUnmounted(() => {
    cancel()
  })
  
  return {
    value: debouncedValue,
    isPending,
    setValue,
    cancel,
    flush
  }
}

// 节流 Composable
export const useThrottle = <T>(
  value: Ref<T> | T,
  delay: number = 300,
  options: Omit<ThrottleConfig, 'delay'> = {}
) => {
  const { leading = true, trailing = true } = options
  
  const throttledValue = ref<T>(typeof value === 'object' && value != null && 'value' in value ? value.value : value) as Ref<T>
  const isPending = ref(false)
  
  const updateValue = (newValue: T) => {
    throttledValue.value = newValue
    isPending.value = false
  }
  
  const throttledUpdate = throttle(updateValue, delay, options)
  
  // 如果传入的是 ref，监听其变化
  if (typeof value === 'object' && value && 'value' in value) {
    watch(
      value,
      (newValue) => {
        isPending.value = true
        throttledUpdate(newValue)
      },
      { immediate: true }
    )
  }
  
  // 手动设置值
  const setValue = (newValue: T) => {
    isPending.value = true
    throttledUpdate(newValue)
  }
  
  // 取消节流
  const cancel = () => {
    throttledUpdate.cancel()
    isPending.value = false
  }
  
  // 立即执行
  const flush = () => {
    throttledUpdate.flush()
    isPending.value = false
  }
  
  // 清理
  onUnmounted(() => {
    cancel()
  })
  
  return {
    value: throttledValue,
    isPending,
    setValue,
    cancel,
    flush
  }
}

// 防抖函数 Composable
export const useDebounceFn = <T extends (...args: any[]) => any>(
  fn: T,
  delay: number = 300,
  options: Omit<DebounceConfig, 'delay'> = {}
) => {
  const debouncedFn = debounce(fn, delay, options)
  
  // 清理
  onUnmounted(() => {
    debouncedFn.cancel()
  })
  
  return debouncedFn
}

// 节流函数 Composable
export const useThrottleFn = <T extends (...args: any[]) => any>(
  fn: T,
  delay: number = 300,
  options: Omit<ThrottleConfig, 'delay'> = {}
) => {
  const throttledFn = throttle(fn, delay, options)
  
  // 清理
  onUnmounted(() => {
    throttledFn.cancel()
  })
  
  return throttledFn
}

// 异步防抖 Composable
export const useAsyncDebounce = <T extends (...args: any[]) => Promise<any>>(
  fn: T,
  delay: number = 300,
  options: Omit<DebounceConfig, 'delay'> = {}
) => {
  const isLoading = ref(false)
  const error = ref<Error | null>(null)
  const data = ref<Awaited<ReturnType<T>> | null>(null)
  
  const execute = async (...args: Parameters<T>): Promise<Awaited<ReturnType<T>> | null> => {
    try {
      isLoading.value = true
      error.value = null
      const result = await fn(...args)
      data.value = result
      return result
    } catch (err) {
      error.value = err instanceof Error ? err : new Error(String(err))
      return null
    } finally {
      isLoading.value = false
    }
  }
  
  const debouncedExecute = useDebounceFn(execute, delay, options)
  
  return {
    execute: debouncedExecute,
    isLoading,
    error,
    data,
    cancel: debouncedExecute.cancel,
    flush: debouncedExecute.flush,
    pending: debouncedExecute.pending
  }
}

// 搜索防抖 Composable
export const useSearchDebounce = (
  searchFn: (query: string) => Promise<any>,
  delay: number = 300
) => {
  const query = ref('')
  const results = ref<any[]>([])
  const isLoading = ref(false)
  const error = ref<Error | null>(null)
  
  const search = async (searchQuery: string) => {
    if (!searchQuery.trim()) {
      results.value = []
      return
    }
    
    try {
      isLoading.value = true
      error.value = null
      const data = await searchFn(searchQuery)
      results.value = Array.isArray(data) ? data : [data]
    } catch (err) {
      error.value = err instanceof Error ? err : new Error(String(err))
      results.value = []
    } finally {
      isLoading.value = false
    }
  }
  
  const debouncedSearch = useDebounceFn(search, delay)
  
  // 监听查询变化
  watch(query, (newQuery) => {
    if (newQuery != null) debouncedSearch(newQuery)
  })
  
  // 清除结果
  const clear = () => {
    query.value = ''
    results.value = []
    error.value = null
    debouncedSearch.cancel()
  }
  
  return {
    query,
    results,
    isLoading,
    error,
    search: debouncedSearch,
    clear
  }
}

// 滚动防抖 Composable
export const useScrollDebounce = (
  callback: (event: Event) => void,
  delay: number = 100
) => {
  const isScrolling = ref(false)
  
  const handleScroll = (event: Event) => {
    isScrolling.value = true
    callback(event)
  }
  
  const debouncedCallback = useDebounceFn(() => {
    isScrolling.value = false
  }, delay)
  
  const scrollHandler = (event: Event) => {
    handleScroll(event)
    debouncedCallback()
  }
  
  return {
    scrollHandler,
    isScrolling,
    cancel: debouncedCallback.cancel
  }
}

// 窗口大小变化防抖 Composable
export const useResizeDebounce = (
  callback: (size: { width: number; height: number }) => void,
  delay: number = 250
) => {
  const isResizing = ref(false)
  const size = ref({
    width: typeof window !== 'undefined' ? window.innerWidth : 0,
    height: typeof window !== 'undefined' ? window.innerHeight : 0
  })
  
  const handleResize = () => {
    isResizing.value = true
    const newSize = {
      width: window.innerWidth,
      height: window.innerHeight
    }
    size.value = newSize
    callback(newSize)
  }
  
  const debouncedCallback = useDebounceFn(() => {
    isResizing.value = false
  }, delay)
  
  const resizeHandler = () => {
    handleResize()
    debouncedCallback()
  }
  
  // 自动绑定事件
  if (typeof window !== 'undefined') {
    window.addEventListener('resize', resizeHandler)
    
    onUnmounted(() => {
      window.removeEventListener('resize', resizeHandler)
      debouncedCallback.cancel()
    })
  }
  
  return {
    size,
    isResizing,
    cancel: debouncedCallback.cancel
  }
}

// 输入防抖 Composable（专门用于表单输入）
export const useInputDebounce = (
  initialValue: string = '',
  delay: number = 300
) => {
  const inputValue = ref(initialValue)
  const debouncedValue = ref(initialValue)
  const isPending = ref(false)
  
  const updateDebouncedValue = (value: string) => {
    debouncedValue.value = value
    isPending.value = false
  }
  
  const debouncedUpdate = useDebounceFn(updateDebouncedValue, delay)
  
  watch(inputValue, (newValue) => {
    isPending.value = true
    debouncedUpdate(newValue)
  })
  
  return {
    inputValue,
    debouncedValue,
    isPending,
    cancel: debouncedUpdate.cancel,
    flush: debouncedUpdate.flush
  }
}

// 类型已在文件开头导出